package cn.zglbk.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 作者： 猪哥亮
 * 时间： 2017/10/31.
 * 描述：byte个进本数据类型的相互转换（直接抄袭dubbo的代码）
 */
public class ByteUtils {
    private static final String C64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    private static final char[] BASE16 = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    private static final char[] BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
    private static final int MASK4 = 15;
    private static final int MASK6 = 63;
    private static final int MASK8 = 255;
    private static final Map<Integer, byte[]> DECODE_TABLE_MAP = new ConcurrentHashMap();
    private static ThreadLocal<MessageDigest> MD = new ThreadLocal();

    private ByteUtils() {
    }

    public static byte[] copyOf(byte[] src, int length) {
        byte[] dest = new byte[length];
        System.arraycopy(src, 0, dest, 0, Math.min(src.length, length));
        return dest;
    }

    public static byte[] short2bytes(short v) {
        byte[] ret = new byte[]{0, 0};
        short2bytes(v, ret);
        return ret;
    }

    public static void short2bytes(short v, byte[] b) {
        short2bytes(v, b, 0);
    }

    public static void short2bytes(short v, byte[] b, int off) {
        b[off + 1] = (byte) v;
        b[off + 0] = (byte) (v >>> 8);
    }

    public static byte[] int2bytes(int v) {
        byte[] ret = new byte[]{0, 0, 0, 0};
        int2bytes(v, ret);
        return ret;
    }

    public static void int2bytes(int v, byte[] b) {
        int2bytes(v, b, 0);
    }

    public static void int2bytes(int v, byte[] b, int off) {
        b[off + 3] = (byte) v;
        b[off + 2] = (byte) (v >>> 8);
        b[off + 1] = (byte) (v >>> 16);
        b[off + 0] = (byte) (v >>> 24);
    }

    public static byte[] float2bytes(float v) {
        byte[] ret = new byte[]{0, 0, 0, 0};
        float2bytes(v, ret);
        return ret;
    }

    public static void float2bytes(float v, byte[] b) {
        float2bytes(v, b, 0);
    }

    public static void float2bytes(float v, byte[] b, int off) {
        int i = Float.floatToIntBits(v);
        b[off + 3] = (byte) i;
        b[off + 2] = (byte) (i >>> 8);
        b[off + 1] = (byte) (i >>> 16);
        b[off + 0] = (byte) (i >>> 24);
    }

    public static byte[] long2bytes(long v) {
        byte[] ret = new byte[]{0, 0, 0, 0, 0, 0, 0, 0};
        long2bytes(v, ret);
        return ret;
    }

    public static void long2bytes(long v, byte[] b) {
        long2bytes(v, b, 0);
    }

    public static void long2bytes(long v, byte[] b, int off) {
        b[off + 7] = (byte) ((int) v);
        b[off + 6] = (byte) ((int) (v >>> 8));
        b[off + 5] = (byte) ((int) (v >>> 16));
        b[off + 4] = (byte) ((int) (v >>> 24));
        b[off + 3] = (byte) ((int) (v >>> 32));
        b[off + 2] = (byte) ((int) (v >>> 40));
        b[off + 1] = (byte) ((int) (v >>> 48));
        b[off + 0] = (byte) ((int) (v >>> 56));
    }

    public static byte[] double2bytes(double v) {
        byte[] ret = new byte[]{0, 0, 0, 0, 0, 0, 0, 0};
        double2bytes(v, ret);
        return ret;
    }

    public static void double2bytes(double v, byte[] b) {
        double2bytes(v, b, 0);
    }

    public static void double2bytes(double v, byte[] b, int off) {
        long j = Double.doubleToLongBits(v);
        b[off + 7] = (byte) ((int) j);
        b[off + 6] = (byte) ((int) (j >>> 8));
        b[off + 5] = (byte) ((int) (j >>> 16));
        b[off + 4] = (byte) ((int) (j >>> 24));
        b[off + 3] = (byte) ((int) (j >>> 32));
        b[off + 2] = (byte) ((int) (j >>> 40));
        b[off + 1] = (byte) ((int) (j >>> 48));
        b[off + 0] = (byte) ((int) (j >>> 56));
    }

    public static short bytes2short(byte[] b) {
        return bytes2short(b, 0);
    }

    public static short bytes2short(byte[] b, int off) {
        return (short) (((b[off + 1] & 255) << 0) + (b[off + 0] << 8));
    }

    public static int bytes2int(byte[] b) {
        return bytes2int(b, 0);
    }

    public static int bytes2int(byte[] b, int off) {
        return ((b[off + 3] & 255) << 0) + ((b[off + 2] & 255) << 8) + ((b[off + 1] & 255) << 16) + (b[off + 0] << 24);
    }

    public static float bytes2float(byte[] b) {
        return bytes2float(b, 0);
    }

    public static float bytes2float(byte[] b, int off) {
        int i = ((b[off + 3] & 255) << 0) + ((b[off + 2] & 255) << 8) + ((b[off + 1] & 255) << 16) + (b[off + 0] << 24);
        return Float.intBitsToFloat(i);
    }

    public static long bytes2long(byte[] b) {
        return bytes2long(b, 0);
    }

    public static long bytes2long(byte[] b, int off) {
        return (((long) b[off + 7] & 255L) << 0) + (((long) b[off + 6] & 255L) << 8) + (((long) b[off + 5] & 255L) << 16) + (((long) b[off + 4] & 255L) << 24) + (((long) b[off + 3] & 255L) << 32) + (((long) b[off + 2] & 255L) << 40) + (((long) b[off + 1] & 255L) << 48) + ((long) b[off + 0] << 56);
    }

    public static double bytes2double(byte[] b) {
        return bytes2double(b, 0);
    }

    public static double bytes2double(byte[] b, int off) {
        long j = (((long) b[off + 7] & 255L) << 0) + (((long) b[off + 6] & 255L) << 8) + (((long) b[off + 5] & 255L) << 16) + (((long) b[off + 4] & 255L) << 24) + (((long) b[off + 3] & 255L) << 32) + (((long) b[off + 2] & 255L) << 40) + (((long) b[off + 1] & 255L) << 48) + ((long) b[off + 0] << 56);
        return Double.longBitsToDouble(j);
    }

    public static String bytes2hex(byte[] bs) {
        return bytes2hex(bs, 0, bs.length);
    }

    public static String bytes2hex(byte[] bs, int off, int len) {
        if (off < 0) {
            throw new IndexOutOfBoundsException("bytes2hex: offset < 0, offset is " + off);
        } else if (len < 0) {
            throw new IndexOutOfBoundsException("bytes2hex: length < 0, length is " + len);
        } else if (off + len > bs.length) {
            throw new IndexOutOfBoundsException("bytes2hex: offset + length > array length.");
        } else {
            int r = off;
            int w = 0;
            char[] cs = new char[len * 2];

            for (int i = 0; i < len; ++i) {
                byte b = bs[r++];
                cs[w++] = BASE16[b >> 4 & 15];
                cs[w++] = BASE16[b & 15];
            }

            return new String(cs);
        }
    }

    public static byte[] hex2bytes(String str) {
        return hex2bytes(str, 0, str.length());
    }

    public static byte[] hex2bytes(String str, int off, int len) {
        if ((len & 1) == 1) {
            throw new IllegalArgumentException("hex2bytes: ( len & 1 ) == 1.");
        } else if (off < 0) {
            throw new IndexOutOfBoundsException("hex2bytes: offset < 0, offset is " + off);
        } else if (len < 0) {
            throw new IndexOutOfBoundsException("hex2bytes: length < 0, length is " + len);
        } else if (off + len > str.length()) {
            throw new IndexOutOfBoundsException("hex2bytes: offset + length > array length.");
        } else {
            int num = len / 2;
            int r = off;
            int w = 0;
            byte[] b = new byte[num];

            for (int i = 0; i < num; ++i) {
                b[w++] = (byte) (hex(str.charAt(r++)) << 4 | hex(str.charAt(r++)));
            }

            return b;
        }
    }


    public static byte[] getMD5(String str) {
        return getMD5(str.getBytes());
    }

    public static byte[] getMD5(byte[] source) {
        MessageDigest md = getMessageDigest();
        return md.digest(source);
    }

    public static byte[] getMD5(File file) throws IOException {
        FileInputStream is = new FileInputStream(file);

        byte[] var2;
        try {
            var2 = getMD5((InputStream) is);
        } finally {
            is.close();
        }

        return var2;
    }

    public static byte[] getMD5(InputStream is) throws IOException {
        return getMD5(is, 8192);
    }

    private static byte hex(char c) {
        if (c <= '9') {
            return (byte) (c - 48);
        } else if (c >= 'a' && c <= 'f') {
            return (byte) (c - 97 + 10);
        } else if (c >= 'A' && c <= 'F') {
            return (byte) (c - 65 + 10);
        } else {
            throw new IllegalArgumentException("hex string format error [" + c + "].");
        }
    }

    private static int indexOf(char[] cs, char c) {
        int i = 0;

        for (int len = cs.length; i < len; ++i) {
            if (cs[i] == c) {
                return i;
            }
        }

        return -1;
    }

    private static byte[] decodeTable(String code) {
        int hash = code.hashCode();
        byte[] ret = (byte[]) DECODE_TABLE_MAP.get(hash);
        if (ret == null) {
            if (code.length() < 64) {
                throw new IllegalArgumentException("Base64 code length < 64.");
            }

            ret = new byte[128];

            int i;
            for (i = 0; i < 128; ++i) {
                ret[i] = -1;
            }

            for (i = 0; i < 64; ++i) {
                ret[code.charAt(i)] = (byte) i;
            }

            DECODE_TABLE_MAP.put(hash, ret);
        }

        return ret;
    }

    private static byte[] getMD5(InputStream is, int bs) throws IOException {
        MessageDigest md = getMessageDigest();

        for (byte[] buf = new byte[bs]; is.available() > 0; md.update(buf)) {
            int total = 0;

            int read;
            while ((read = is.read(buf, total, bs - total)) > 0) {
                total += read;
                if (total >= bs) {
                    break;
                }
            }
        }

        return md.digest();
    }

    private static MessageDigest getMessageDigest() {
        MessageDigest ret = (MessageDigest) MD.get();
        if (ret == null) {
            try {
                ret = MessageDigest.getInstance("MD5");
                MD.set(ret);
            } catch (NoSuchAlgorithmException var2) {
                throw new RuntimeException(var2);
            }
        }

        return ret;
    }
    /**
     * 获取字节高四位
     * @param data
     * @return
     */
    public static int getHeight4(byte data){
        int height;
        height = ((data & 0xf0) >> 4);
        return height;
    }

    /**
     * 获取字节低四位
     * @param data
     * @return
     */
    public static int getLow4(byte data){
        int low;
        low = (data & 0x0f);
        return low;
    }
    public static String byte2bite(byte by){
        StringBuffer sb = new StringBuffer();
        sb.append((by>>7)&0x1)
                .append((by>>6)&0x1)
                .append((by>>5)&0x1)
                .append((by>>4)&0x1)
                .append((by>>3)&0x1)
                .append((by>>2)&0x1)
                .append((by>>1)&0x1)
                .append((by>>0)&0x1);
        return sb.toString();
    }
    public static byte bit2byte(String bit) {
        int re, len;
        if (null == bit) {
            return 0;
        }
        len = bit.length();
        if (len != 4 && len != 8) {
            return 0;
        }
        // 8 bit处理
        if (len == 8) {
            // 正数
            if (bit.charAt(0) == '0') {
                re = Integer.parseInt(bit, 2);
            } else {
                // 负数
                 re = Integer.parseInt(bit, 2) - 256;
            }
        } else {
            //4 bit处理
            re = Integer.parseInt(bit, 2);
        }
        return (byte) re;
    }

    public static void main(String[] args) {
        //状态码解析拼装
        //1=成功，2=失败
        //消息类型
        //1=请求响应。2=主动通知
        //1-1
        System.out.println(bit2byte("00010001"));
        //2-1
        System.out.println(bit2byte("00100001"));
        //2-2
        System.out.println(bit2byte("00100010"));
        //1-2
        System.out.println(bit2byte("00010010"));

    }
}